package com.bestv.search.management.command;

import com.bestv.search.common.cache.SystemCache;
import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.*;
import com.bestv.search.common.model.uid.UID;
import com.bestv.search.common.service.BizTypeManager;
import com.bestv.search.common.service.InfoHeaderItemManager;
import com.bestv.search.common.service.InfoHeaderManager;
import com.bestv.search.common.service.InfoManager;
import com.bestv.search.common.util.PropertyStrategyWrapper;
import com.bestv.search.common.util.StringConst;
import net.sf.json.JsonConfig;
import net.sf.json.util.PropertySetStrategy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class InfoHeaderCommand {
    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    protected final Log log = LogFactory.getLog(getClass());
    private InfoHeaderManager infoHeaderManager;
    private BizTypeManager bm;
    private InfoHeaderItemManager infoHeaderItemManager;
    private InfoManager infoManager;
    private SystemCache systemCache;

    public String getInfoHeaderByName(SysUser user, HttpServletRequest request, DataSourceKey dsKey) {
        String keyword = request.getParameter("keyword");
        String start = request.getParameter("start");
        String limit = request.getParameter("limit");
        String headerType = request.getParameter("headerType");

        // Start
        int startInt = 0;
        try {
            startInt = Integer.parseInt(start);
        } catch (Exception e) {
            log.warn("Parse start node to integer error!");
            startInt = 0;
        }

        // Limit
        int limitInt = 0;
        try {
            limitInt = Integer.parseInt(limit);
        } catch (Exception e) {
            log.warn("Parse start node to integer error!");
            limitInt = 20;
        }

        List<InfoHeader> list = infoHeaderManager.getInfoHeaderLikeName(dsKey, keyword, headerType, startInt, limitInt);
        int total = infoHeaderManager.getInfoHeaderCountLikeName(dsKey, keyword, headerType);

        return convertInfoHeaderToJson(list, total);
    }

    public String updateInfoHeaderStatus(SysUser user, HttpServletRequest request, DataSourceKey dsKey) {
        String code = request.getParameter("code");
        String status = request.getParameter("status");
        int statusInt = 0;
        try {
            statusInt = Integer.parseInt(status);
        } catch (Exception e) {
            log.warn("Parse start node to integer error!");
            statusInt = 0;
        }

        InfoHeader infoHeader = infoHeaderManager.get(dsKey, code);
        infoHeader.setUpdate_time_for_index(new Date());
        infoHeader.setStatus(statusInt);
        infoHeaderManager.saveOrUpdate(dsKey, infoHeader);

        return "success";
    }

    public String getInfoHeaderItemByHeaderId(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String[] headerId = map.get("headerId");
        if (headerId == null || headerId.length == 0) {
            log.error("Please provide headerId !");
            return "{'totalCount:0, results:[error]}";
        }

        List<Map<String, String>> items = infoHeaderManager.getInfoHeaderItemByHeaderId(dsKey,
                Long.valueOf(headerId[0]));

        JSONArray array = new JSONArray();
        if (items != null) {
            for (Map<String, String> item : items) {
                JSONObject json = new JSONObject();
                try {
                    json.put("itemName", item.get("name"));
                    json.put("contentFlag", item.get("content_flag"));
                    json.put("itemOrder", item.get("info_order"));
                    json.put("contentVersion",
                            item.get("content_version") == null ? StringConst.EMPTY : item.get("content_version"));
                    json.put("itemDescription",
                            item.get("description") == null ? StringConst.EMPTY : item.get("description"));
                    json.put("id", item.get("id") == null ? StringConst.EMPTY : String.valueOf(item.get("id")));
                    array.put(json);
                } catch (JSONException e) {
                    log.error("Convert to Json object failed.");
                    e.printStackTrace();
                }
            }
        }
        return "{'totalCount':" + (items == null ? 0 : items.size()) + ",'results':" + array.toString() + "}";
    }

    public String createOrEditInfoHeader(SysUser user, HttpServletRequest request, DataSourceKey dsKey) {

        String headerJSON = null;
        String removeItemsJSON = null;
        String saveOrUpdateItemsJSON = null;
        try {
            headerJSON = new String(request.getParameter("header").getBytes(StringConst.ISO_8859_1), StringConst.GBK);
            removeItemsJSON = new String(request.getParameter("removeItems").getBytes(StringConst.ISO_8859_1),
                    StringConst.GBK);
            saveOrUpdateItemsJSON = new String(request.getParameter("saveOrUpdateItems").getBytes(
                    StringConst.ISO_8859_1), StringConst.GBK);
        } catch (UnsupportedEncodingException e) {
            log.error("Save infoHeader failed, due to exception,");
            e.printStackTrace();
            return "failed";
        }

        boolean isNew = Boolean.parseBoolean(request.getParameter("isNew"));
        // Save or update header
        InfoHeader header = convertJSONTOObject(headerJSON, new InfoHeader());

        List<InfoHeader> headers = infoHeaderManager.get(dsKey, header.getName(), header.getP_type());
        if (isNew && headers != null && headers.size() > 0) {
            return "exist";
        }

        if (header.getReleasedStr() != null && !header.getReleasedStr().equals(StringConst.EMPTY)) {
            try {
                header.setReleased(format.parse(header.getReleasedStr()));
            } catch (ParseException e) {
                log.error("Data format shold be like yyyy-MM-dd, but data is " + header.getReleasedStr());
                e.printStackTrace();
            }
        }
        BizType bizType = bm.getBizTypeByName(dsKey, header.getP_type());
        if (bizType == null) {
            bizType = new BizType();
            bizType.setPtype(header.getP_type());
            // default to 3
            bizType.setLevel(3);
            bizType.setValue(header.getP_type());
            bm.saveBizTypes(dsKey, bizType);
            bizType = bm.getBizTypeByName(dsKey, header.getP_type());
        }
        header.setBizType(bizType);
        long headerId = saveOrUpdateInfoHeader(header, isNew, dsKey);

        // delete InfoHeaderItem
        List<InfoHeaderItem> deleteItems = convertJSONTOList(removeItemsJSON, new InfoHeaderItem());
        if (deleteItems != null && deleteItems.size() > 0) {
            infoHeaderItemManager.removeInfoItems(dsKey, deleteItems);
        }

        List<InfoHeaderItem> saveOrUpdateItems = convertJSONTOList(saveOrUpdateItemsJSON, new InfoHeaderItem());
        saveOrUpdateInfoHeaderItems(saveOrUpdateItems, headerId, dsKey);

        return "success";
    }

    private long saveOrUpdateInfoHeader(InfoHeader header, boolean isNew, DataSourceKey dsKey) {
        if (isNew) {
            header.setId(new Long(UID.getUID(header)));
            header.setCode(header.getHeaderType()
                    + StringConst.UNDERLINE
                    + systemCache.getLocalDataSourceKey()
                    + StringConst.UNDERLINE
                    + (header.getP_type() == null ? StringConst.EMPTY : String.valueOf(Math.abs(header.getP_type()
                    .hashCode())) + String.valueOf(Math.abs(header.getName().hashCode()))));
            header.setStatus(1);
            header.setUpdate_time_for_index(new Date());
            header.setLast_update_time(new Date());
            infoHeaderManager.saveOrUpdate(dsKey, header);
        } else {
            InfoHeader headerInDB = infoHeaderManager.get(dsKey, header.getId());
            headerInDB.setName(header.getName());
            headerInDB.setAlias_name(header.getAlias_name());
            headerInDB.setHeaderType(header.getHeaderType());
            headerInDB.setGenre(header.getGenre());
            headerInDB.setTags(header.getTags());
            headerInDB.setWriters(header.getWriters());
            headerInDB.setActors(header.getActors());
            headerInDB.setRegion(header.getRegion());
            headerInDB.setReleased(header.getReleased());
            headerInDB.setP_type(header.getP_type());
            headerInDB.setBizType(header.getBizType());
            headerInDB.setDescription(header.getDescription());
            headerInDB.setClarity_flag(header.getClarity_flag());
            headerInDB.setIsCharge(header.getIsCharge());
            headerInDB.setLanguage(header.getLanguage());
            headerInDB.setCategory(header.getCategory());
            headerInDB.setContent_crowd(header.getContent_crowd());
            headerInDB.setKeywords(header.getKeywords());
            headerInDB.setUpdate_time_for_index(new Date());
            headerInDB.setLast_update_time(new Date());
            infoHeaderManager.saveOrUpdate(dsKey, headerInDB);
        }

        return header.getId();
    }

    private void saveOrUpdateInfoHeaderItems(List<InfoHeaderItem> items, long headerId, DataSourceKey dsKey) {
        List<InfoHeaderItem> saveOrUpdateItems = new ArrayList<InfoHeaderItem>();
        if (items != null && items.size() > 0) {
            for (InfoHeaderItem item : items) {
                InfoHeaderItem itemInDB = infoHeaderItemManager.get(dsKey, item.getInfo_header_id(), item.getInfo_id());
                if (itemInDB != null) {
                    itemInDB.setDescription(item.getDescription());
                    itemInDB.setInfo_order(item.getInfo_order());
                    itemInDB.setContentFlag(item.getContentFlag());
                    itemInDB.setContentVersion(item.getContentVersion());
                    itemInDB.setUpdateTime(new Date());
                    saveOrUpdateItems.add(itemInDB);
                } else {
                    item.setUpdateTime(new Date());
                    item.setInfo_header_id(headerId);
                    saveOrUpdateItems.add(item);
                }
            }
            infoHeaderItemManager.saveOrUpdate(dsKey, saveOrUpdateItems);
            infoManager.saveOrUpdateInfoByInfoHeaderItems(dsKey, saveOrUpdateItems);
        }
    }

    private <T> List<T> convertJSONTOList(String json, T t) {

        net.sf.json.JSONArray jsonArray = (net.sf.json.JSONArray) net.sf.json.JSONArray.fromObject(json);
        JsonConfig jsonConfig = new JsonConfig();
        jsonConfig.setPropertySetStrategy(new PropertyStrategyWrapper(PropertySetStrategy.DEFAULT));
        jsonConfig.setRootClass(t.getClass());
        jsonConfig.setArrayMode(JsonConfig.MODE_LIST);
        @SuppressWarnings("unchecked")
        List<T> results = (List<T>) net.sf.json.JSONSerializer.toJava(jsonArray, jsonConfig);

        return results;
    }

    @SuppressWarnings("unchecked")
    private <T> T convertJSONTOObject(String json, T t) {

        net.sf.json.JSONObject jsonDetails = net.sf.json.JSONObject.fromObject(json);
        JsonConfig detailcfg = new JsonConfig();
        detailcfg.setPropertySetStrategy(new PropertyStrategyWrapper(PropertySetStrategy.DEFAULT));
        detailcfg.setRootClass(t.getClass());
        t = (T) net.sf.json.JSONObject.toBean(jsonDetails, detailcfg);

        return t;
    }

    public String getHeaderDetailByCode(SysUser user, HttpServletRequest request, DataSourceKey dsKey) {
        String code = request.getParameter("code");
        InfoHeader header = infoHeaderManager.get(dsKey, code);

        JSONObject headerToJson = new JSONObject();
        try {
            headerToJson.put("id", String.valueOf(header.getId()));
            headerToJson.put("name", header.getName());
            headerToJson.put("aliasName", header.getAlias_name() == null ? StringConst.EMPTY : header.getAlias_name());
            headerToJson.put("headerType", header.getHeaderType() == null ? StringConst.EMPTY : header.getHeaderType());
            headerToJson.put("genre", header.getGenre() == null ? StringConst.EMPTY : header.getGenre());
            headerToJson.put("tags", header.getTags() == null ? StringConst.EMPTY : header.getTags());
            headerToJson.put("writers", header.getWriters() == null ? StringConst.EMPTY : header.getWriters());
            headerToJson.put("actors", header.getActors() == null ? StringConst.EMPTY : header.getActors());
            headerToJson.put("region", header.getRegion() == null ? StringConst.EMPTY : header.getRegion());
            headerToJson.put("released",
                    header.getReleased() == null ? StringConst.EMPTY : format.format(header.getReleased()));
            headerToJson.put("description",
                    header.getDescription() == null ? StringConst.EMPTY : header.getDescription());
            headerToJson.put("clarityFlag", header.getClarity_flag());
            headerToJson.put("p_type", header.getP_type());
            headerToJson.put("isCharge", header.getIsCharge());
            headerToJson.put("language", header.getLanguage() == null ? StringConst.EMPTY : header.getLanguage());
            headerToJson.put("category", header.getCategory() == null ? StringConst.EMPTY : header.getCategory());
            headerToJson
                    .put("crowd", header.getContent_crowd() == null ? StringConst.EMPTY : header.getContent_crowd());
            headerToJson.put("keyword", header.getKeywords() == null ? StringConst.EMPTY : header.getKeywords());
        } catch (JSONException e) {
            log.error("Convert to Json object failed.");
            e.printStackTrace();
        }

        JSONArray results = new JSONArray();
        results.put(headerToJson);

        return results.toString();
    }

    private String convertInfoHeaderToJson(List<InfoHeader> list, int total) {
        JSONArray array = new JSONArray();
        int i = 0;
        for (InfoHeader info : list) {
            JSONObject json = new JSONObject();
            try {
                json.put("name", info.getName());
                json.put("bizType", info.getP_type());
                json.put("code", info.getCode());
                json.put("writeDisplay", info.getWriters());
                json.put("actorDisplay", info.getActors());
                json.put("status", info.getStatus());
                json.put("index", i++);
                array.put(json);
            } catch (JSONException e) {
                log.error("Convert to Json object failed.");
                e.printStackTrace();
            }
        }

        return "{'totalCount':" + total + ",'results':" + array.toString() + "}";
    }

    public void updateInfoHeadersTimeAndStatus(List<Info> infos) {
        DataSourceKey dsKey = DataSourceKeyUtil.convert(systemCache.getLocalDataSourceKey());

        // Gets all infoHeaderIds by infoId
        Set<Long> infoHeaderIds = new HashSet<Long>();
        for (Info info : infos) {
            List<InfoHeaderItem> infoItems = infoHeaderItemManager.getAllInfoHeaderItemByInfoId(dsKey, info.getId());
            for (InfoHeaderItem infoItem : infoItems) {
                infoHeaderIds.add(infoItem.getInfo_header_id());
            }
        }

        // Updates status, updateTime by infoHeaderIds
        for (Long infoHeaderId : infoHeaderIds) {
            InfoHeader header = infoHeaderManager.get(dsKey, infoHeaderId.longValue());
            int count = infoHeaderManager.getItemCountByHeaderId(dsKey, infoHeaderId.longValue());

            // Doesn't exist any on line info, so offline this header
            if (count == 0) {
                header.setStatus(0);
            } else {
                header.setStatus(1);
            }

            header.setUpdate_time_for_index(new Date());
            header.setLast_update_time(new Date());

            infoHeaderManager.saveOrUpdate(dsKey, header);
        }
    }

    public void updateInfoHeadersTimeAndStatus(Info info) {
        List<Info> list = new ArrayList<Info>(1);
        list.add(info);
        this.updateInfoHeadersTimeAndStatus(list);
    }

    public InfoHeaderManager getInfoHeaderManager() {
        return infoHeaderManager;
    }

    public void setInfoHeaderManager(InfoHeaderManager infoHeaderManager) {
        this.infoHeaderManager = infoHeaderManager;
    }

    public BizTypeManager getBm() {
        return bm;
    }

    public void setBm(BizTypeManager bm) {
        this.bm = bm;
    }

    public InfoHeaderItemManager getInfoHeaderItemManager() {
        return infoHeaderItemManager;
    }

    public void setInfoHeaderItemManager(InfoHeaderItemManager infoHeaderItemManager) {
        this.infoHeaderItemManager = infoHeaderItemManager;
    }

    public InfoManager getInfoManager() {
        return infoManager;
    }

    public void setInfoManager(InfoManager infoManager) {
        this.infoManager = infoManager;
    }

    public SystemCache getSystemCache() {
        return systemCache;
    }

    public void setSystemCache(SystemCache systemCache) {
        this.systemCache = systemCache;
    }
}